﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Chessboard.cs" company="">
//   
// </copyright>
//  <summary>
//   The chessboard.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Shatranj
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;

    /// <summary>
    /// The chessboard.
    /// </summary>
    public class Chessboard : IChessboard, INotifyPropertyChanged
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Chessboard"/> class.
        /// </summary>
        public Chessboard()
        {
            this.LoadSquares();
            this.Initialize();
        }

        #endregion

        #region Public Events

        /// <summary>
        /// The property changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the active square.
        /// </summary>
        public BoardSquare ActiveSquare { get; set; }

        /// <summary>
        /// Gets or sets the all squares.
        /// </summary>
        public ObservableCollection<BoardSquare> AllSquares { get; set; }

        /// <summary>
        /// Gets or sets the captured pieces.
        /// </summary>
        public IDictionary<Army, ChessPiece> CapturedPieces { get; set; }

        /// <summary>
        /// Gets or sets the current turn.
        /// </summary>
        public Turn CurrentTurn { get; set; }

        /// <summary>
        /// Gets or sets the files.
        /// </summary>
        public BoardFile[] Files { get; set; }

        /// <summary>
        /// Gets or sets the squares.
        /// </summary>
        public BoardSquare[,] Squares { get; set; }

        #endregion

        #region Public Indexers

        /// <summary>
        /// The this.
        /// </summary>
        /// <param name="position">
        /// The position.
        /// </param>
        /// <returns>
        /// The <see cref="BoardSquare"/>.
        /// </returns>
        public BoardSquare this[string position]
        {
            get
            {
                var pos = PositionCalculator.Parse(position);
                return this.Squares[pos.X, pos.Y];
            }

            set
            {
                var pos = PositionCalculator.Parse(position);
                this.Squares[pos.X, pos.Y] = value;
                this.OnPropertyChanged(this, new PropertyChangedEventArgs(string.Format("Square{0}", position)));
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The layout pieces.
        /// </summary>
        public void LayoutPieces()
        {
        }

        // TODO: Can this be layout pieces?

        /// <summary>
        /// The make move.
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <exception cref="NotImplementedException">
        /// </exception>
        public void MakeMove(BoardLocation source, BoardLocation target)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// The make move.
        /// </summary>
        /// <param name="sourceAlgebraicNotation">
        /// The source algebraic notation.
        /// </param>
        /// <param name="targetAlgebraicNotation">
        /// The target algebraic notation.
        /// </param>
        public void MakeMove(string sourceAlgebraicNotation, string targetAlgebraicNotation)
        {
            var spos = PositionCalculator.Parse(sourceAlgebraicNotation);
            var tpos = PositionCalculator.Parse(targetAlgebraicNotation);
            var source = this.Squares[spos.X, spos.Y];
            var target = this.Squares[tpos.X, tpos.Y];
            if (source.IsEmpty)
            {
                return;
            }

            if (!target.IsEmpty && target.CurrentPiece.Force == source.CurrentPiece.Force)
            {
                // Can't capture your own piece
                return;
            }

            var piece = source.CurrentPiece;
            source.CurrentPiece = null;
            target.CurrentPiece = piece;
            this.OnPropertyChanged(this, new PropertyChangedEventArgs("AllSquares"));
        }

        /// <summary>
        /// The make move.
        /// </summary>
        /// <param name="piece">
        /// The piece.
        /// </param>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <exception cref="NotImplementedException">
        /// </exception>
        public void MakeMove(ChessPiece piece, BoardLocation target)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// The prepare to move.
        /// </summary>
        /// <param name="piece">
        /// The piece.
        /// </param>
        public void PrepareToMove(ChessPiece piece)
        {
            MoveCalculator.Calculate(piece, piece.CurrentLocation, MoveOptions.AllApplicable);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The on property changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            var handler = this.PropertyChanged;
            this.PropertyChanged(this, args);
        }

        /// <summary>
        /// The initialize.
        /// </summary>
        private void Initialize()
        {
            this.Squares[0, 0].CurrentPiece = new Rook(this.Squares[0, 0], Army.White);
            this.Squares[0, 1].CurrentPiece = new Knight(this.Squares[0, 1], Army.White);
            this.Squares[0, 2].CurrentPiece = new Bishop(this.Squares[0, 2], Army.White);
            this.Squares[0, 3].CurrentPiece = new Queen(this.Squares[0, 3], Army.White);
            this.Squares[0, 4].CurrentPiece = new King(this.Squares[0, 4], Army.White);
            this.Squares[0, 5].CurrentPiece = new Bishop(this.Squares[0, 5], Army.White);
            this.Squares[0, 6].CurrentPiece = new Knight(this.Squares[0, 6], Army.White);
            this.Squares[0, 7].CurrentPiece = new Rook(this.Squares[0, 7], Army.White);

            for (int i = 1; i < 2; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    this.Squares[i, j].CurrentPiece = new Pawn(this.Squares[i, j], Army.White);
                }
            }

            for (int i = 6; i < 7; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    this.Squares[i, j].CurrentPiece = new Pawn(this.Squares[i, j], Army.Black);
                }
            }

            this.Squares[7, 0].CurrentPiece = new Rook(this.Squares[7, 0], Army.Black);
            this.Squares[7, 1].CurrentPiece = new Knight(this.Squares[7, 2], Army.Black);
            this.Squares[7, 2].CurrentPiece = new Bishop(this.Squares[7, 1], Army.Black);
            this.Squares[7, 3].CurrentPiece = new Queen(this.Squares[7, 3], Army.Black);
            this.Squares[7, 4].CurrentPiece = new King(this.Squares[7, 4], Army.Black);
            this.Squares[7, 5].CurrentPiece = new Bishop(this.Squares[7, 6], Army.Black);
            this.Squares[7, 6].CurrentPiece = new Knight(this.Squares[7, 5], Army.Black);
            this.Squares[7, 7].CurrentPiece = new Rook(this.Squares[7, 7], Army.Black);

            this.LinkSquares();
        }

        /// <summary>
        /// The link squares.
        /// </summary>
        private void LinkSquares()
        {
            for (var i = 0; i < 8; i++)
            {
                for (var j = 0; j < 8; j++)
                {
                    var square = this.Squares[i, j];

                    if (j > 0)
                    {
                        square.East = this.Squares[i, j - 1];
                        if (i < 7 && j > 0)
                        {
                            square.Northeast = this.Squares[i + 1, j - 1];
                        }

                        if (j > 0 && i > 0)
                        {
                            square.Southeast = this.Squares[i - 1, j - 1];
                        }
                    }

                    if (i < 7)
                    {
                        square.North = this.Squares[i + 1, j];
                    }

                    if (i > 0)
                    {
                        square.South = this.Squares[i - 1, j];
                    }

                    if (j < 7)
                    {
                        square.West = this.Squares[i, j + 1];

                        if (i < 7)
                        {
                            square.Northwest = this.Squares[i + 1, j + 1];
                        }

                        if (i > 0)
                        {
                            square.Southwest = this.Squares[i - 1, j + 1];
                        }
                    }
                }
            }
        }

        /// <summary>
        /// The load squares.
        /// </summary>
        private void LoadSquares()
        {
            this.Squares = new BoardSquare[8, 8];
            this.AllSquares = new ObservableCollection<BoardSquare>();
            for (var i = 0; i < 8; i++)
            {
                for (var j = 0; j < 8; j++)
                {
                    this.Squares[i, j] = new BoardSquare(this);
                    this.AllSquares.Add(this.Squares[i, j]);
                    this.Squares[i, j].AlgebraicIdentity = string.Concat((char)('a' + j),  i + 1);
                }
            }
        }

        #endregion
    }
}